Опубликован: 06.12.2011 | Доступ: свободный | Студентов: 3557 / 746 | Оценка: 4.50 / 4.39 | Длительность: 03:42:00
Лекция 5:

Разработка расчетной подсистемы: расчет показателей, перерасчеты

< Лекция 4 || Лекция 5: 12345 || Лекция 6 >

Рассмотрим этот код. Когда мы завершили формирование (но не расчет) записей регистров расчета в модуле документа НачислениеЗарплаты, мы вызываем экспортную процедуру РассчитатьЗарплату() из общего модуля РасчетЗарплаты. В свою очередь, из этой процедуры производится вызов еще двух методов – один – РассчитатьОсновныеНачисления() вызывается для расчета начислений, внесенных в регистр ОсновныеНачисления документом, из которого была вызвана процедура РассчитатьЗарплату(), вторая – РассчитатьДополнительныеНачисления() – для расчета дополнительных начислений.

В процедуре РассчитатьЗарплату мы создаем копии наборов записей регистров расчета ОсновныеНачисления и ДополнительныеНачисления, отбирая записи по параметру Регистратор – то есть – по ссылке на документ, из которого была вызвана процедура.

После создания копий необходимых записей, мы открываем цикл перебора перечисления КатегорииРасчета. При переборе значения перечисления присваиваются переменной цикла Категория в соответствии с порядком их расположения в настройках перечисления в Конфигураторе. Таким образом, этот цикл последовательно проходит по категориям расчета Первичное, Зависимое первого уровня, Зависимое второго уровня. Смысл этого цикла заключается в том, чтобы виды расчета с более высоким приоритетом были бы рассчитаны раньше, чем виды расчета с более низкими приоритетами. Все дело в том, что, например, виды расчета, относящиеся к категории расчета Первичное, могут быть рассчитаны независимо от других видов расчета. Их мы рассчитываем в первую очередь. Виды расчета с категорией Зависимое первого уровня опираются на первичные виды расчета, и, в свою очередь, Зависимые второго уровня могут опираться на две предыдущие категории.

В цикле мы вызываем процедуры РассчитатьОсновныеНачисления() и РассчитатьДополнительныеНачисления(). При вызове этих процедур мы передаем им схожие наборы параметров. Так, это параметр Регистратор – он пригодится нам для дальнейшей работы, это параметры НаборЗаписейОсн и НаборЗаписейДоп – наборы записей регистров, полученные ранее, а так же параметр Категория – основываясь на переданной категории расчета мы будем, внутри процедур расчета записей, принимать решения о том, какие записи нужно рассчитать при текущем значении категории расчета.

Рассмотрим метод РассчитатьОсновныеНачисления().

В начале мы получаем параметры базы для расчета начислений, использующих базовый период с помощью команды:

База=РегистрыРасчета.ОсновныеНачисления.ПолучитьБазу(ОтборРегистратор, Ресурсы, Измерения);

Перед вызовом данной команды мы формируем структуры данных для получения базы. Во-первых – это структура Измерения, в которой находятся измерения регистра расчета для получения базы. Во-вторых – это массив Ресурсы – он содержит значения, которые позволяют нам получить, суммовые показатели расчетной базы и показатели количества отработанных дней по базовым видам расчета. В-третьих – это структура ОтборРегистратор – она позволяет отобрать данные по регистратору.

Полученная переменная База – это таблица значений, содержащая нужные данные по базовым видам расчета.

Далее, мы открываем цикл перебора записей в полученном ранее наборе записей регистра НаборЗаписейОсн, и, при входе в цикл, проверяем, принадлежит ли запись к рассчитываемой при данном вызове метода РассчитатьОсновныеНачисления() категории расчета. Если это так, мы переходим к формированию расчетных показателей, в противном случае переходим к следующей итерации цикла перебора записей.

При выполнении условия на проверку категории расчета мы получаем следующие данные:

БазаЗаписи – суммовой показатель по расчетной базе. Расчетная база собирается в соответствии с базовым периодом, указанным при вводе записи, и в соответствии с набором базовых видов расчета, указанных при настройке вида расчета, используемого в записи. Например, если мы рассчитываем Отпуск, базой для которого служит Оклад и базовый период для расчета показателя Отпуск равняется трем месяцам, в показатель БазаЗаписи попадут все начисления Оклада за эти три месяца. Если в один из месяцев оклад равнялся 10000 рублей, во втором – 12000, в третьем – 11000, в показателе БазаЗаписи мы получим 10000+12000+11000=33000 рублей.

МетодРасчета – метод расчета, указанный для вида расчета, который используется в текущей записи.

ДнейФактЗаписи – фактический период для текущей записи. Например, если мы рассчитываем оклад, с которым связан график Пятидневка и в месяце, за который производится оклад, 21 день, причем, за счет вытеснения другими видами расчета (прогулом, например), оказывается, что фактически работник отработал лишь 19 дней, в переменной ДнейФактЗаписи окажется значение именно 19 дней.

ДнейПланЗаписи – показатель, характеризующий общее число дней в периоде действия записи. В вышеописанном примере сюда попадет именно 21 день.

ДнейБазаЗаписи – в этой переменной окажется количество дней, которое соответствует отработанным дням для базовых видов расчета. Например, если вид расчета Отпуск рассчитывается за три месяца и базой для этого вида расчета является Оклад, причем, в одном из месяцев работник отработал 19 дней, во втором – 11, в третьем – 20 – мы получим в данном показателе 19+11+20=50 отработанных дней.

ИсходныеДанные – это тот показатель, который мы задаем при вводе информации о начислении. Для вида расчета Оклад – это сумма оклада, которую сотрудник получил бы, отработав полный месяц, для Оклада по дням – это сумма оплаты за один отработанный день.

ВлияетНаОтработанноеВремя – сюда мы записываем значение реквизита ВлияетНаОтработанноеВремя вида расчета, соответствующего текущей записи. На основе анализа этой переменной мы будем либо увеличивать число отработанных дней, либо не будем этого делать.

Далее следует ряд проверок показателя МетодРасчета на соответствии его значениям перечисления МетодыРасчета. В зависимости от значения этого показателя используются различные методы расчета.

Для метода ФиксированнаяСумма мы, без каких-либо дополнительных изменений, переносим значение из свойства ИсходныеДанные в свойство Сумма.

Для метода Процент мы умножаем расчетную базу на процент, заданный при вводе записи. Так как проценты мы вводим в виде 10%, 50% и т.д., мы, для получения верного результата, делим ИсходныеДанные на 100.

Для метода По дням мы получаем количество фактически отработанных дней и умножаем полученное число дней на ИсходныеДанные, в которых, в данном случае, хранится сумма оплаты за один день.

Для метода ПоСреднему мы делим суммовой показатель базы (БазаЗаписи) на количество отработанных дней в базовом периоде (ДнейБазаЗаписи) и умножаем полученный результат (то есть – размер среднедневной оплаты труда) на количество дней, которое должно быть оплачено по начислению, для которого производится расчет.

Для метода ПоОтработанномуВремени мы умножаем ИсходныеДанные на отношение фактически отработанного времени к полному времени, которое мог бы отработать сотрудник в периоде, для которого производится расчет.

После завершения расчета в соответствии с методом расчета, мы проверяем, влияет ли рассчитываемая запись на количество отработанных дней, если влияет – устанавливаем параметр ДнейОтработано в значение фактически отработанных дней по данной записи.

Далее мы проверяем, является ли обрабатываемая запись сторнировочной, то есть – такой, которая отражает в текущем периоде уточнения для записей, выполненных в предыдущем периоде. Если является – инвертируем знак у суммы, которая ранее была записана, и у количества отработанных дней. Если оказалось, что в текущем периоде был введен вид расчета, который уменьшает показатели начислений предыдущих периодов (например, в текущем периоде введен Прогул за предыдущий период, вытесняющий Оклад, который уже начислен), сторнировочная запись позволит отразить в текущем периоде корректировочный показатель, не затрагивая данных предыдущих периодов.

В итоге мы записываем набор записей командой НаборЗаписейОсн.Записать;

Теперь рассмотрим метод РассчитатьДополнительныеНачисления(). В начале мы получаем расчетую базу (База) такими же методами, как и выше, для записей регистра ОсновныеНачисления. Разница здесь заключается лишь в том, что записи регистра расчета ДополнительныеНачисления могут включать расчетную базу, сформированную как в регистре ДополнительныеНачисления, так и в регистре ОсновныеНачисления. Поэтому, создавая структуру отбора по измерениям мы указываем измерения двух регистров, создавая массив отбора по ресурсам мы, так же, указываем два суммовых показателя, на которые нужно ориентироваться системе при формировании расчетной базы.

Далее мы входим в цикл обработки набора записей регистра ДополнительныеНачисления, сверяем категорию расчета текущей записи с категорией расчета, которая передана в процедуру при ее вызове (это, напомним, позволяет нам рассчитать записи в соответствии с порядком их расчета, что позволит правильно получить расчетную базу для зависимых видов расчета). Если категория расчета совпадает с переданной, мы переходим к расчету показателей.

Показатели данного регистра не оперируют понятием периода действия, они характеризуются датой начисления и суммой (или другим алгоритмом расчета, не учитывающим отработанное время). И в данном регистре мы используем виды расчета, которые рассчитываются двумя методами – процентом и фиксированной суммой. Расчет этих показателей аналогичен вышеописанному.

Виды расчета из плана видов расчета ДополнительныеНачисления не увеличивают отработанное время, для них мы не формируем сторнировочных записей (механизмы вытеснения в данном регистре не используются), в итоге, после расчета показателей мы записываем сформированные записи.

После завершения в процедуре РассчитатьЗарплату цикла обхода перечисления КатегорииРасчета мы выводим пользователю сообщение о том, что расчет зарплаты по текущему документу завершен.

Нужно отметить, что главная цель вышеприведенного кода – максимально понятная демонстрация достаточно сложных механизмов работы с регистрами расчета. Для повышения быстродействия данного кода его следует проанализировать и вынести как можно больше команд, формирующих запросы к системе (ПолучитьДанныеГрафика, ПолучитьБазу) из циклов, оформив их в виде запросов. Количество запросов так же следует минимизировать. Однако, наш код выполняет возложенные на него функции, поэтому мы не будем заниматься его оптимизацией, перейдем к проверке результатов расчета.

После написания любого кода, как и в процессе написания, следует постоянно проверять правильность его работы. В случае с достаточно сложными расчетными механизмами следует внимательно проверить результаты их работы. В частности, нужно проверить расчет всех возможных видов расчета с "ручным" контролем правильности результатов, проверить расчет зависимых видов расчета, так же проконтролировав его. В противном случае нельзя гарантировать правильность работы механизмов. В случае возникновения ошибок, особенно таких, которые не вызывают системных сообщений об ошибках, нужно внимательно проанализировать записи регистров расчетов, сформированные документами, обратив особое внимание на следующее:

  • Верно ли данные из табличных частей документа переносятся в регистры расчета?
  • Верно ли заполняются периоды (Базовый, ПериодДействия)?
  • Правильно ли заполнены графики?
  • Правильно ли настроены параметры графика в регистре расчета?
  • Правильно ли настроены виды расчета в планах видов расчета (состав базовых и вытесняющих видов расчета, реквизиты видов расчета)?
  • Правильно ли получены исходные данные для расчета записей в расчетных процедурах?
  • Нет ли ошибок в алгоритмах расчета показателей?
  • В правильном ли порядке рассчитываются показатели, относящиеся к различным категориям расчетов?

В проверке весьма полезно использовать инструменты отладки – точки останова, остановку по ошибке (Отладка > Остановка по ошибке), окно вычисления выражения.

< Лекция 4 || Лекция 5: 12345 || Лекция 6 >
Константин Павлов
Константин Павлов

Почему в лекции 1 "Основы организации бухгалтерской подсистемы" курса "Разработка прикладных решений для платформы 1С:Предприятие 8.2 в режиме "Управляемое приложение"" совершенно нет информации о том что нужно на вкладке данные в табличной части создать табличную часть "ВидыСубконто" и также нет информации о том какие нужно добавить реквизиты и какие у этих реквизитов должен быть тип? Считаю лекцию 1 в данном вопросе недоработанной.

Надежда Федулкина
Надежда Федулкина